/*
 * Saphre - Suffix Arrays for Phrase Extraction
 * Copyright (C) 2013 
 * Dale Gerdemann - Tübingen, Germany 
 * Niko Schenk - Frankfurt am Main, Germany
 * All rights reserved.
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package saphre.core;

import util.Interval;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import saphre.concordance.Concordance;
import saphre.concordance.ConcordanceOverlap;
import saphre.commands.CmdExcludeRev;
import saphre.commands.CmdGappy;
import saphre.commands.CmdRepeats;
import saphre.commands.CmdKeywordSearch;
import saphre.commands.CmdLengthenL;
import saphre.commands.CmdLengthenR;
import saphre.commands.CmdMaximals;
import saphre.commands.CmdMaximalsByThreshold;
import saphre.commands.CmdRepeatsByThreshold;
import saphre.commands.CmdPalindrome;
import saphre.commands.CmdPathInterval;
import saphre.commands.CmdPrintConcordance;
import saphre.commands.CmdShowAlpha;
import saphre.commands.CmdShowInterval;
import saphre.commands.CmdShowInterval2;
import saphre.commands.CmdShowMemInterval;
import saphre.commands.CmdShowSigma;
import saphre.commands.CmdSuffLink;
import saphre.commands.CmdSupPhrase;
import saphre.commands.CmdSuperMaximals;

/**
 * This class represents a central handler for commands 
 * available in Saphre.
 * 
 * 
 * @author Niko Schenk
 */
public class SaphreCommandInterpreter {

    SuffixArray pa = null;
    
    // Core commands.
    // Discontinuous, "gappy" phrases.
    private final CmdGappy cmdGappy = new CmdGappy(); 
    // General repeated ngrams.
    private final CmdRepeats cmdRepeats = new CmdRepeats();
    // Maximal, supermaximal and general phrases (repeats).
    private final CmdMaximals cmdMaximals = new CmdMaximals();
    private final CmdMaximalsByThreshold cmdMaximalsByThreshold = new CmdMaximalsByThreshold();
    private final CmdSuperMaximals cmdSuperMaximals = new CmdSuperMaximals();
    private final CmdRepeatsByThreshold cmdRepeatsByThreshold = new CmdRepeatsByThreshold();
    
    // Default. It's a keyword search. Print concordance (keyword in context).
    private final CmdKeywordSearch cmdKeywordSearch = new CmdKeywordSearch();
    private final CmdPrintConcordance cmdPrintConcordance = new CmdPrintConcordance();
    
    
    
    // Experimental commands.
    private final CmdShowSigma cmdShowSigma = new CmdShowSigma();
    private final CmdShowAlpha cmdShowAlpha = new CmdShowAlpha();
    private final CmdLengthenR cmdLengthenR = new CmdLengthenR();
    private final CmdLengthenL cmdLengthenL = new CmdLengthenL();
    private final CmdExcludeRev cmdExcludeRev = new CmdExcludeRev();
    private final CmdPalindrome cmdPalindrome = new CmdPalindrome();
    private final CmdSuffLink cmdSuffLink = new CmdSuffLink(this);
    private final CmdShowInterval cmdShowInterval = new CmdShowInterval();
    private final CmdShowMemInterval cmdShowMemInterval = new CmdShowMemInterval(this);
    private final CmdShowInterval2 cmdShowInterval2 = new CmdShowInterval2(this);
    private final CmdPathInterval cmdPathInterval = new CmdPathInterval();
    private final CmdSupPhrase cmdSupPhrase = new CmdSupPhrase();
    
    

    public enum SaphreCommands {

        // Discontinuous (discontiguous/"gapped"/"gappy") phrases/repeats.
        // TODO: Improve statistics calculation for gappy phrases.
        
        // TODO: Add a measure for "homegeneity" / uniformity 
        // of term frequency distribution for fillers.
        // For example, fillers: tf: 40, 44, 22, 55, 32 is better than 1, 2222, 3344, 8.
        CmdGappy("\\s*show:gappy"
                // Everything combined.
                + "(\\s+minGap=(\\d+))?" // min gap size
                + "(\\s+maxGap=(\\d+))?" // max gap size
                + "(\\s+minMiLeftRightPart=(\\d+(\\.\\d+)?))?" // min mutual information of left and right association
                + "(\\s+minCombinedAverageMiYamamotoChurch=(\\d+(\\.\\d+)?))?" // min combined average mi Y&C
                + "(\\s+minGlobalRidf=(\\d+(\\.\\d+)?))?" // min global residual idf
                + "(\\s+minTf=(\\d+))?" // min term frequency of gappy phrase (A note on the definition...)
                + "(\\s+minDf=(\\d+))?" // min document frequency of gappy phrase (A note on the definition...)
                // Left context.
                + "(\\s+minLengthLP=(\\d+))?" // min length of left part
                + "(\\s+maxLengthLP=(\\d+))?" // max length of left part
                + "(\\s+minTfLP=(\\d+))?" // min tf of left part in corpus
                + "(\\s+maxTfLP=(\\d+))?" // max tf of left part in corpus
                + "(\\s+minRidfLP=(\\d+(\\.\\d+)?))?" // min ridf of left part in corpus
                + "(\\s+inLP=(\"[A-Za-z0-9äöüÄÖÜß\\-\\ ]+\"))?" // substring contained within left part
                // Right context.
                + "(\\s+minLengthRP=(\\d+))?" // min length of right part
                + "(\\s+maxLengthRP=(\\d+))?" // max length of right part
                + "(\\s+minTfRP=(\\d+))?" // min tf of right part in corpus
                + "(\\s+maxTfRP=(\\d+))?" // max tf of right part in corpus
                + "(\\s+minRidfRP=(\\d+(\\.\\d+)?))?" // min ridf of right part in corpus
                + "(\\s+inRP=(\"[A-Za-z0-9äöüÄÖÜß\\-\\ ]+\"))?" // substring contained within right part
                // Fillers.
                + "(\\s+minNumberFI=(\\d+))?" // min number of fillers
                + "(\\s+minSumTfFI=(\\d+))?" // min sum tf of fillers
                + "(\\s+minAverageRidfFI=(\\d+(\\.\\d+)?))?" // min average ridf of all fillers
                + "(\\s+minMaxfill=(\\d+(\\.\\d+)?))?" // min proportion of maximal fillers
                + "(\\s+minRatio=(\\d+))?" // ratio of sumTfOfFillers divided by num fillers.
                + "(\\s+inFI=(\"[A-Za-z0-9äöüÄÖÜß\\-\\ ]+\"))?" // term as a substring of all fillers
                // Print options.
                + "(\\s+writeToFile=(true|t|f|false|0|1))?" // produce junk on hard drive
                + "(\\s+printToConsole=(true|t|f|false|0|1))?"), // spam to standard out
        
        
        // General repeats.
        CmdRepeats("\\s*show:repeats"
                + "(\\s+minLength=(\\d+))?"
                + "(\\s+maxLength=(\\d+))?"
                + "(\\s+minTf=(\\d+))?"
                + "(\\s+minMiYamamotoChurch=(\\d+(\\.\\d+)?))?"
                + "(\\s+minMiGeneral=(\\d+(\\.\\d+)?))?"
                + "(\\s+minRidf=(\\d+(\\.\\d+)?))?"
                + "(\\s+startsWith=(.+))?"
                + "(\\s+contains=(.+))?"
                + "(\\s+writeToFile=(true|t|f|false|0|1))?"
                + "(\\s+printToConsole=(true|t|f|false|0|1))?"),
        
        // Maximal repeats.
        CmdMaximalRepeats("\\s*show:maximals(\\s+minLength=(\\d+))?(\\s+maxLength=(\\d+))?(\\s+minTf=(\\d+))?(\\s+startsWith=(.+))?"),
        
        // Maximal repeats by threshold.
        CmdMaximalRepeatsByThreshold("\\s*show:maximalsByThreshold(\\s+minLength=(\\d+))?(\\s+maxLength=(\\d+))?(\\s+minTf=(\\d+))?(\\s+startsWith=(.+))?(\\s+minHowmaxL=(\\d+(\\.\\d+)?))?(\\s+minHowmaxR=(\\d+(\\.\\d+)?))?"),
        
        // Supermaximal repeat.
        CmdSuperMaximalRepeats("\\s*show:supermaximals(\\s+minLength=(\\d+))?(\\s+maxLength=(\\d+))?(\\s+minTf=(\\d+))?(\\s+startsWith=(.+))?"),
        
        
        // TODO: Repeats with paremeterizable thresholds for "howmaximal".
        CmdRepeatsByThreshold("\\s*show:repeatsByThreshold(\\s+minLength=(\\d+))?(\\s+maxLength=(\\d+))?(\\s+minTf=(\\d+))?(\\s+startsWith=(.+))?(\\s+minHowmax=(\\d+))?(\\s+maxHowmax=(\\d+))?"),
        
        
        // TODO:
        // Frequency histogram. (unigram, bigram, stopwords.)
        
        
        // TODO: 
        // Get sorted list of mutual information bigrams, trigrams, make 
        // mutual information computation parameterizable.
        
        
        CmdSupPhrase("\\s*show:supPhrase"),
        CmdShowSigma("\\s*show:sigma"),
        CmdShowAlpha("\\s*show:alpha"),
        CmdText("\\s*text\\s*:\\s*(\\d+),(\\d+)"),
        CmdWConcord("\\s*\\?\\?\\s*:\\s*(.+)?"),
        CmdExcludeRev("\\s*show\\s*:revExclude"),
        CmdLengthenL("\\s*collect\\s*:lengthenl"),
        CmdLengthenR("\\s*collect\\s*:lengthenr"),
        CmdPalindrome("\\s*show\\s*:palindrome"),
        CmdSuffLink("\\s*show\\s*:suffLink"),
        CmdShowTop("\\s*show\\s*:top"),
        CmdShowInterval("\\s*interval\\s*:\\s*(\\d+),\\s*(\\d+)(,\\s*(\\d*)?)?"),
        CmdShowMemInterval("\\s*(p|s)interval\\s*:\\s*(-?\\d+),\\s*(-?\\d+)(,\\s*(\\d*)?)?"),
        CmdShowInterval2("\\s*interval:(pa|sa)(?:,(-?[0-9]+)(?:,([0-9]+)(?:,([0-9]+))?)?)?"),
        CmdDocName("\\s*doc\\s*:(\\d+)"),
        CmdPathInterval("\\s*path\\s*:\\s*(\\d+),\\s*(\\d+)"),
        CmdExtend("\\s*extend\\s*:(.*)"),
        CmdPrintConcordance("\\s*collect\\s*:printCC");
        
        
        private final String index;

        SaphreCommands(String index) {
            this.index = index;
        }

        public String searchPattern() {
            return index;
        }
    }

    public SaphreCommandInterpreter() {
    }

    /**
     * Interpret query as a Saphre command.
     *
     * @param store
     * @param delMap
     * @param N
     * @param sa
     * @param pa
     * @param top
     * @param concord
     * @param concordOver
     * @param q
     * @param args
     */
    public void interpretCommand(Store store, Map<String, List<Interval>> delMap,
            int N, SuffixArray sa, SuffixArray pa, Interval top,
            Concordance concord, ConcordanceOverlap concordOver,
            String q, String[] args) {

        if (pa == null) {
            pa = sa.prefixArray();
            this.pa = pa;
        }

        SaphreCommands selectedCommand = null;
        for (SaphreCommands cmd : SaphreCommands.values()) {
            // System.out.println(cmd + " " + cmd.searchPattern());
            /*  if (Pattern.matches(cmd.searchPattern(), q)) {*/
            if (Pattern.compile(cmd.searchPattern()).matcher(q).matches()) {
                selectedCommand = cmd;
                break;
            }
        }


        // We found no specific (specified) command.
        // Interpret the command as a simple search query for a word in the corpus
        // and return a KWIC (keyword in context) view.
        if (selectedCommand == null) {
            System.out.println("No predefinded command found for your query.\n"
                    + "Interpreting your command as a keyword search...");

            cmdKeywordSearch.searchForKeyword(store, pa, sa, top, concord, q);
            return; // no valid command found, exit method.
        }


        // Check which predefined command was selected.
        Pattern patternDaddy = Pattern.compile(selectedCommand.searchPattern());
        Matcher m = patternDaddy.matcher(q);

         // Extract discontinuous phrases.
        if (selectedCommand == SaphreCommands.CmdGappy) {
            m.matches();
            cmdGappy.executeCommandGappy(store, pa, top, sa,  m);
        }
        
        // General repeats.
        if (selectedCommand == SaphreCommands.CmdRepeats) {
            m.matches();
            cmdRepeats.extractRepeats(store, sa, pa, top, m);
        }
        // Maximal phrases.
        if (selectedCommand == SaphreCommands.CmdMaximalRepeats) {
            m.matches();
            cmdMaximals.extractMaximalPhrases(store, sa, pa, top, m);
        }
        // Maximal phrases by threshold on howmax (left / right).
        if (selectedCommand == SaphreCommands.CmdMaximalRepeatsByThreshold) {
            m.matches();
            cmdMaximalsByThreshold.extractMaximalPhrasesByThreshold(store, sa, pa, top, m);
        }
        // Supermaximal phrases.
        if (selectedCommand == SaphreCommands.CmdSuperMaximalRepeats) {
            m.matches();
            cmdSuperMaximals.extractSuperMaximalPhrases(store, sa, pa, top, m);
        }
        
        // Maximal phrases by threshold on 'howmax'
        if (selectedCommand == SaphreCommands.CmdRepeatsByThreshold) {
            m.matches();
            cmdRepeatsByThreshold.extractRepeatsByThreshold(store, sa, pa, top, m);
        }
        
        // Extract n-grams and their "best" extensions rated by the mutual information.
        if (selectedCommand == SaphreCommands.CmdSupPhrase) {
            cmdSupPhrase.showSupPhrase(store, sa, pa, top, sa.N);
        }
        

        if (selectedCommand == SaphreCommands.CmdShowAlpha) {
            cmdShowAlpha.showAlpha(store, sa, pa, top, concordOver);
        }

        if (selectedCommand == SaphreCommands.CmdShowSigma) {
            cmdShowSigma.showSigma(store);
        }

        if (selectedCommand == SaphreCommands.CmdPrintConcordance) {
            cmdPrintConcordance.CmdPrintConcordance(store, sa, top, args);
        }

        if (selectedCommand == SaphreCommands.CmdText) {
            m.matches();
            System.out.println("Retrieving text indices:");
            System.out.println(store.toString(Integer.parseInt(m.group(1)),
                    Integer.parseInt(m.group(2))));
        }

        if (selectedCommand == SaphreCommands.CmdExcludeRev) {
            pa = cmdExcludeRev.CmdExcludeRev(store, sa, pa, top);
            this.pa = pa;
        }

        if (selectedCommand == SaphreCommands.CmdLengthenL) {
            cmdLengthenL.CmdLengthenL(store, sa, pa, top);
        }

        if (selectedCommand == SaphreCommands.CmdLengthenR) {
            cmdLengthenR.CmdLengthenR(store, sa, pa, top);
        }

        if (selectedCommand == SaphreCommands.CmdPalindrome) {
            cmdPalindrome.CmdPalindrome(store, sa, top);
        }

        if (selectedCommand == SaphreCommands.CmdSuffLink) {
            cmdSuffLink.CmdSuffLink(store, N, sa, top);
        }

        if (selectedCommand == SaphreCommands.CmdShowTop) {
            System.out.println(top);
        }

        if (selectedCommand == SaphreCommands.CmdShowInterval) {
            cmdShowInterval.CmdShowInterval(store, sa, pa, m);
        }

        if (selectedCommand == SaphreCommands.CmdShowMemInterval) {
            cmdShowMemInterval.CmdShowMemInterval(store, sa, pa, m);
        }

        if (selectedCommand == SaphreCommands.CmdShowInterval2) {
            cmdShowInterval2.CmdShowInterval2(store, sa, pa, m);
        }

        if (selectedCommand == SaphreCommands.CmdDocName) {
            m.matches();
            int pos = Integer.parseInt(m.group(1));
            System.out.println(store.docNameOfPos(pos));
        }

        if (selectedCommand == SaphreCommands.CmdPathInterval) {
            cmdPathInterval.CmdPathInterval(store, pa, top, m);
        }
    }
}
